<script setup>
import * as THREE from "three";
import {GLTFLoader} from "three/addons/loaders/GLTFLoader.js";
import {OrbitControls} from "three/addons/controls/OrbitControls.js";
import { Line2 } from 'three/addons/lines/Line2.js';
import {TubeGeometry} from 'three'
import {LineGeometry} from "three/addons";
import {ShaderMaterial, Color, DoubleSide, MathUtils, Vector2} from 'three'
import {LineMaterial } from "three/addons";

let mtlList = []

class View {
  constructor({
      canvas,
      width,
      height,
      cameraPosition,
      fieldOfView = 50,
  }){
    this.posList = [
      {name: '枪机摄像头', pos: new THREE.Vector3(-5, 5, 0), transform: new THREE.Vector3(-5, 5, 0), scale: new THREE.Vector3(.6, .6, .6), path: '/models/security_camera/scene.gltf'},
      {name: '球机摄像头', pos: new THREE.Vector3(0, 5, 0), transform: new THREE.Vector3(0, 5, 0), scale: new THREE.Vector3(.4, .4, .4), path: '/models/security_camera (1)/scene.gltf'},
      {name: '视联网服务器', pos: new THREE.Vector3(-5, 0, 0), transform: new THREE.Vector3(-5, -1, 0), scale: new THREE.Vector3(1, 1, 1), path: '/models/server/scene.gltf'},
      {name: 'AI服务器', pos: new THREE.Vector3(0, 0, 0), transform: new THREE.Vector3(0, -1, 0), scale: new THREE.Vector3(1, 1, 1), path: '/models/server/scene.gltf'},
      {name: '视联网用户端', pos: new THREE.Vector3(5, 0, 0), transform: new THREE.Vector3(5, 0, 0), scale: new THREE.Vector3(.3, .3, .3), path: '/models/sci_-_fi_computer_game_ready/scene.gltf'},
      {name: 'AI用户端', pos: new THREE.Vector3(0, -5, 0), transform: new THREE.Vector3(0, -5, 0), scale: new THREE.Vector3(1.7, 1.7, 1.7), path: '/models/personal_computer/scene.gltf'},
    ]
    this.width = width || window.innerWidth;
    this.height = height || window.innerHeight;
    this.aspectRatio = this.width / this.height;
    this.camera = new THREE.PerspectiveCamera(
        fieldOfView,
        this.aspectRatio
    );
    this.camera.position.set(
        cameraPosition.x,
        cameraPosition.y,
        cameraPosition.z
    );
    this.camera.lookAt(new THREE.Vector3(0, 0, 0));
    this.renderer = new THREE.WebGLRenderer({
      canvas,
      alpha: true,
      antialias: true
    });
    this.scene = new THREE.Scene();
    this.clock = new THREE.Clock();
    this.time = { current: 0, t0: 0, t1: 0, t: 0, frequency: 0.0005 };
    this.tubes = []
    this.scene.add(this.camera);
    this.renderer.setSize(this.width, this.height);

    // this.control = new OrbitControls(this.camera, canvas)
    this.addModel()
    this.addLight()
    this.addAxes()
    this.addLineMtl()
    this.addLine([
        this.posList[0].pos,
        this.posList[2].pos
    ])
    this.addLine([
        this.posList[1].pos,
        this.posList[2].pos
    ])
    this.addLine([
        this.posList[2].pos,
        this.posList[3].pos
    ])
    this.addLine([
        this.posList[3].pos,
        this.posList[4].pos
    ])
    this.addLine([
        this.posList[3].pos,
        this.posList[5].pos
    ])
  }
  render(){
    this.renderer.render(this.scene, this.camera);
    this.composer && this.composer.render();
  }
  animate() {
    this.render();
    // console.log(this.lineMaterial);
    /*if(this.lineMaterial) {
      this.lineMaterial.uniforms.uTime.value += 0.01;
    }*/
    // 更新所有管道的uTime
    this.tubes.forEach(tube => {
      if (tube.material) {
        tube.material.uniforms.uTime.value += 0.005;
      }
    });
    requestAnimationFrame(this.animate.bind(this));
  }
  async addModel() {
    let serverModel = await this.loadObj(
        "/models/server/scene.gltf"
    );

    for(let objData of this.posList) {
      // console.log('objData',objData);
      let model = await this.loadObj(objData.path);
      model.position.copy(objData.transform)
      model.scale.copy(objData.scale)
      // serverModel.position.set(this.posList[0].pos.x, this.posList[0].pos.y, this.posList[0].pos.z);
      model.name = objData.name
      this.scene.add(model);
    }
    /*this.posList.forEach(objData => {
      let model = this.loadObj(objData.path);
      serverModel.position.copy(objData.pos)
      // serverModel.position.set(this.posList[0].pos.x, this.posList[0].pos.y, this.posList[0].pos.z);
      serverModel.name = objData.name
      this.scene.add(serverModel);
    })*/
  }
  loadObj(path) {
    const loader = new GLTFLoader();
    return new Promise((resolve) => {
      loader.load(
          path,
          (response) => {
            console.log(response);
            resolve(response.scene);
          },
          (xhr) => {},
          (err) => {
            console.log(err);
          }
      );
    });
  }
  listenToResize() {
    window.addEventListener("resize", () => {
      // Update sizes
      this.width = window.innerWidth;
      this.height = window.innerHeight;

      // Update camera
      this.camera.aspect = this.width / this.height;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(this.width, this.height);
    });
  }
  /*addLine(pointArr) {
    // 1. 创建曲线路径（如管道）
    const curve = new THREE.CatmullRomCurve3(pointArr);
    // const points = curve.getPoints(50); // 采样50个点
    // const positions = points.flatMap(p => [p.x, p.y, p.z]);

    for(let l of [-.1,-.08,-.06,-.04,-.02,0,.02,.04,.06,.08,.1]) {
      pointArr.forEach(item => {
        item.x += l; item.y += l; item.z += l;
      })
      const curve = new THREE.CatmullRomCurve3(pointArr);
      // const positions = points.flatMap(p => [p.x + l, p.y + l, p.z + l]);
      // 2. 初始化Line2
      // const geometry = new LineGeometry().setPositions(positions);
      const geometry = new TubeGeometry(curve,this.height, 0.02, 8, false)

      // let mtl = this.lineMaterial.clone()
      // console.log(mtl);
      const line = new Line2(geometry, this.lineMaterial);
      this.scene.add(line);
    }
  }*/
  addLine(pointArr) {
    const curve = new THREE.CatmullRomCurve3(pointArr);
    const points = curve.getPoints(50);

    // 计算曲线法线方向
    const tangent = new THREE.Vector3();
    const normal = new THREE.Vector3();
    const binormal = new THREE.Vector3();
    curve.computeFrenetFrames(50, false);

    // console.log(curve);
    curve.computeFrenetFrames(points.length, false);
    // 获取首点法线作为参考方向
    // const refNormal = curve.frenetFrames.normals[0].clone();

    // 构建平行管道
    const offsets = [-0.1, -0.08, -0.06, -0.04, -0.02, 0, 0.02, 0.04, 0.06, 0.08, 0.1];
    const colors = [
      new Color(0, 0.8, 1),   // 青蓝
      // new Color(0.2, 0.5, 1), // 宝蓝
      new Color(1, 1, 1), // 宝蓝
      // new Color(0.4, 0.3, 1), // 紫蓝
      // new Color(0.1, 0.9, 0.8), // 青绿
      // new Color(0.3, 1, 0.6)   // 荧光绿
    ];

    offsets.forEach((offset, i) => {
      const offsetPoints = points.map(p => {
        // return p.clone().add(refNormal.clone().multiplyScalar(offset));
        console.log(p);
        return p.clone()
      });

      const offsetCurve = new THREE.CatmullRomCurve3(offsetPoints);
      const geometry = new THREE.TubeGeometry(offsetCurve, 64, 0.05, 8, false);

      // 循环使用颜色
      const color = colors[i % colors.length];
      const mtl = this.createLineMaterial(color);

      const tube = new THREE.Mesh(geometry, mtl);
      // tube.position.copy(offset)
      this.scene.add(tube);
      this.tubes.push(tube); // 保存引用用于动画
    });
  }
  addLight() {
    const light = new THREE.AmbientLight( 0xffffff ); // 柔和的白光
    this.scene.add( light );
  }
  addAxes() {
    const axesHelper = new THREE.AxesHelper( 5 );
    this.scene.add( axesHelper );
  }
  addLineMtl() {
    const c = new Color(0,0.6,1);
    const commonUniforms = {
      uFade: { value: new Vector2(0, 0.6) }
    };
    this.lineMaterial = new ShaderMaterial({
      side: DoubleSide,
      transparent: true,
      uniforms: {
        uColor: { value: c },
        uTime: { value: MathUtils.lerp(-1, 1, Math.random()) },
        uDirection: { value: 1 },
        uSpeed: { value: MathUtils.lerp(1, 1.5, Math.random()) },
        ...commonUniforms
      },
      vertexShader: `
                varying vec2 vUv;
                void main(void) {
                    vUv = uv;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);
                }`,
      fragmentShader: `
                varying vec2 vUv;
                uniform float uSpeed;
                uniform float uTime;
                uniform vec2 uFade;
                uniform vec3 uColor;
                uniform float uDirection;
                void main() {
                    vec3 color = uColor;

                   //流动方向
                    float s = -uTime * uSpeed;
                    float v = 0.0;
                    if(uDirection == 1.0) {
                        v = vUv.x;
                    } else {
                        v = -vUv.x;
                    }

                    float d = mod((v + s), 1.0);
                    if(d > uFade.y)
                        discard;
                    else {
                        //平滑透明度渐变
                        float alpha = smoothstep(uFade.x, uFade.y, d);
                        //透明度太小时不显示
                        if(alpha < 0.001)
                            discard;
                        gl_FragColor = vec4(color, alpha);
                    }
                }`
    });
  }
  createLineMaterial(baseColor) {
    return new ShaderMaterial({
      side: DoubleSide,
      transparent: true,
      uniforms: {
        uColor: { value: baseColor },
        uTime: { value: 0 },
        uSpeed: { value: MathUtils.lerp(1.5, 2.5, Math.random()) },
        uThickness: { value: 0.02 }
      },
      vertexShader: `
      varying vec2 vUv;
      varying vec3 vNormal;
      void main() {
        vUv = uv;
        vNormal = normal;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
      fragmentShader: `
      uniform vec3 uColor;
      uniform float uTime;
      uniform float uSpeed;
      uniform float uThickness;
      varying vec2 vUv;
      varying vec3 vNormal;

      void main() {
        // 流动光带效果
        float pulse = sin(20.0 * (vUv.x - uTime * uSpeed));
        float glow = smoothstep(0.3, 0.8, pulse) * 0.8;

        // 边缘光效果
        float edge = 1.0 - abs(dot(normalize(vNormal), vec3(0, 0, 1)));
        edge = pow(edge, 2.0) * 0.6;

        // 组合效果
        vec3 finalColor = uColor * (glow + 0.2 + edge);
        float alpha = smoothstep(0.1, 0.9, glow) * 0.9;

        gl_FragColor = vec4(finalColor, alpha);
      }
    `
    });
  }
}
const webgl = ref()
onMounted(() => {
  nextTick(() => {
    webgl.value.width = window.innerWidth;
    webgl.value.height = window.innerHeight;
    const view = new View({
      canvas: webgl.value,
      width:  webgl.value.width,
      height: webgl.value.height,
      cameraPosition: { x: 0, y: 2, z: 14 }
    })
    view.animate()
  })
})
</script>

<template>
<canvas ref="webgl"></canvas>
</template>

<style scoped lang="scss">

</style>